package edu.hawaii.ics211.exam;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/**
 * A panel for a single exam question.
 * Each panel should contain a label for the question prompt and a text area for the response.
 * Internally, this class should also contain the path to the JUnit test to check the answer.
 * Optionally, there may be a button linking to some supplementary materials.
 * Unfortunately, this bears little resemblance to the ICS 111 ExamQuestion class. 
 * 
 * @author Branden Ogata
 *
 */

@SuppressWarnings("serial")
public class ExamQuestion extends JPanel
{
  /**
   * The text of the question for the user to answer.
   * 
   */
  private JLabel question;
  
  /**
   * The scroll pane for the response area.
   * 
   */
  private JScrollPane answerScroll;
  
  /**
   * The space for the user to type his or her response.
   * 
   */
  private JTextArea answer;
  
  /**
   * The path to the file that will check the correctness of the answer to this question.
   * 
   */
  private String testFile;
  
  /**
   * The number of points that this question is worth.
   * 
   */
  private int points;
  
  /**
   * The button to click on to view supplementary materials such as the API for other classes.
   * 
   */
  private JButton supplementButton;
  
  /**
   * Creates a new ExamQuestion.
   * 
   * @param question The String containing the text of the question.
   * @param signature The String containing the method signature to provide to the user.
   * @param testFile The String containing the name of the test file that checks the answer.
   * @param points The int equal to the number of points awarded for this question.
   * @param supplementTitle The String containing the title of the supplement for this question.
   *                        If this question has no supplementary materials, then this is null.
   * @param supplement The String containing the supplementary materials for this question.
   *                   If this question has no supplementary materials, then this is null.
   *                   
   */
  
  public ExamQuestion(String question, String signature, String testFile, 
                      int points, String supplementTitle, String supplement)
  {
    // Sets up the layout and other details for the overall question panel
    this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
    
    // The question
    this.question = new JLabel(question);
    this.question.setFont(new Font(Font.SERIF, this.question.getFont().getStyle(),
                                               this.question.getFont().getSize() * 2));
    this.question.setAlignmentX(Component.RIGHT_ALIGNMENT);
    this.add(this.question);
    
    // The supplementary materials (if any)
    if (supplement != null)
    {
      JPanel supplementPanel = new JPanel();
      supplementPanel.setLayout(new BorderLayout());
      this.supplementButton = new JButton("Material");
      this.supplementButton.addActionListener(new ButtonListener(supplementTitle, supplement));
      supplementPanel.add(this.supplementButton, BorderLayout.WEST);
      this.add(supplementPanel);
    }
    
    // The answer area
    this.answer = new JTextArea(32, 64);
    this.answer.setFont(new Font(Font.MONOSPACED, this.answer.getFont().getStyle(), 
                                                  this.answer.getFont().getSize()));
    this.answer.setLineWrap(true);
    this.answer.setWrapStyleWord(true);
    this.answer.setTabSize(0);
    this.answer.setAlignmentX(Component.LEFT_ALIGNMENT);
    this.answer.addKeyListener(new KeyboardListener());
    this.answer.setText(signature);
    this.answerScroll = new JScrollPane(this.answer, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                                                     JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    this.add(this.answerScroll);
    
    // The path to the testing class
    this.testFile = testFile;
    
    // The number of points
    this.points = points;
  }
  
  /**
   * Creates a new ExamQuestion without supplementary materials.
   * 
   * @param question The String containing the text of the question.
   * @param signature The String containing the method signature to provide to the user.
   * @param testFile The String containing the name of the test file that checks the answer.
   * @param points The int equal to the number of points awarded for this question.   
   * 
   */
  
  public ExamQuestion(String question, String signature, String testFile, int points)
  {
    this(question, signature, testFile, points, null, null);
  }
  
  /**
   * Returns the question of this ExamQuestion as a String.
   * This removes all of the HTML formatting tags.
   * 
   * @return editedQuestion The String containing the text of the question of this ExamQuestion.
   * 
   */
  
  public String getQuestion()
  {
    String editedQuestion = this.question.getText();
    editedQuestion = editedQuestion.replaceAll("<html>", "").replaceAll("</html>", "");
    editedQuestion = editedQuestion.replaceAll("<br />", "");
    editedQuestion = editedQuestion.replaceAll("&lt;", "<").replaceAll("&gt;", ">");
    
    return editedQuestion;
  }
  
  /**
   * Returns the answer of this ExamQuestion.
   *
   * @return answer The JTextArea containing the answer of this ExamQuestion.
   *
   */
  
  public JTextArea getAnswer()
  {
    return this.answer;
  }

  /**
   * Returns the testPath of this ExamQuestion.
   *
   * @return testPath The String containing the testPath of this ExamQuestion.
   *
   */
  
  public String getTestPath()
  {
    return this.testFile;
  }

  /**
   * Returns the number of points for this ExamQuestion.
   *
   * @return points The int containing the number of points for this ExamQuestion.
   *
   */
  
  public int getPoints()
  {
    return this.points;
  }

  /**
   * Listens for any button presses.
   * 
   */
  
  private class ButtonListener implements ActionListener
  {
    /**
     * The title of the supplementary material.
     * 
     */
    private String supplementTitle;
    
    /**
     * The text to provide as the supplementary material.
     * 
     */
    private String supplement;
    
    /**
     * Initializes the instance variables for this ButtonListener.
     * 
     * @param supplementTitle The String containing the title of the supplement for this question.
     *                        If this question has no supplementary materials, then this is null.
     * @param supplement The String containing the supplementary materials for this question.
     *                   If this question has no supplementary materials, then this is null.
     *                   
     */
    
    public ButtonListener(String supplementTitle, String supplement)
    {
      this.supplementTitle = supplementTitle;
      this.supplement = supplement;
    }
    
    /**
     * Handles any button presses that occur.
     * 
     * @param event The ActionEvent that recorded the button press.
     * 
     */
    
    @Override
    public void actionPerformed(ActionEvent event)
    {
      // If the supplement button was the source
      if (event.getSource() == supplementButton)
      {
        // Place the supplementary material inside the text area
        JTextArea supplementText = new JTextArea(32, 64);
        supplementText.setFont(new Font(Font.MONOSPACED,
                                        supplementText.getFont().getStyle(),
                                        supplementText.getFont().getSize()));            
        supplementText.setText(supplement);
        supplementText.setWrapStyleWord(true);
        supplementText.setLineWrap(true);
        supplementText.setEditable(false);
        JScrollPane supplementScroll = new JScrollPane(supplementText);
        supplementScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        
        // Show the supplementary material as a non-modal dialog
        JDialog supplementDisplay = new JDialog();
        supplementDisplay.setTitle(supplementTitle);
        supplementDisplay.setModal(false);
        supplementDisplay.add(supplementScroll);
        supplementDisplay.pack();
        supplementDisplay.setVisible(true);
      }
    }
  }
  
  /**
   * Listens for keyboard presses.
   * 
   */
  
  private class KeyboardListener extends KeyAdapter
  {
    /**
     * Handles an key release should it occur.
     * 
     * @param event The KeyEvent that detected the key release.
     * 
     */
    
    @Override
    public void keyReleased(KeyEvent event)
    {
      // If the source was the text area
      if (event.getSource() == answer)
      {
        // If the press was an ENTER, then indent the next line
        // (it seems that keyPressed will make the new line automatically)
        if (event.getKeyChar() == KeyEvent.VK_ENTER)
        {
          // The number of spaces to indent by
          String indent = "";
          int caretPosition = answer.getCaretPosition();
          
          // Since this comes after the newline has already been added,
          // the index needs to start two characters before 
          // (one for the newline just added, one for the newline on the line before)
          int index = caretPosition - 2;
          System.out.println(index);
            
          // Find the number of spaces before a non-whitespace character;
          // that will be the number of spaces to use for the indent
          while ((index >= 0) && (answer.getText().charAt(index) != '\n'))
          {
            System.out.println("Entered while loop");
            // If the character is a space, then add one more space to the indent
            if (answer.getText().charAt(index) == ' ')
            {
              indent += " ";
            }
            // Else reset the indent
            else
            {
              indent = "";
            }
 
            index--;
          }
          
          answer.insert(indent, caretPosition);
        }
        // If the press was a TAB, then indent by two spaces
        else if ((event.getKeyChar() == KeyEvent.VK_TAB) && (event.getModifiers() == 0))
        {
          answer.insert("  ", answer.getCaretPosition());
        }
      }
    }    
  }
}
